from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from orders.models import Order, OrderGoods
from users.models import Users, Address
from goods.models import Goods
from datetime import datetime
from django.db import transaction
from alipay import AliPay

import random
import redis
import time

# Create your views here.
"""
创建订单
1.把勾选的要支付的商品获取到
2.当前的用户
3.用户地址
4.支付方式

要把上面所有的数据写入order表
思路:
1.获取上面的数据
2.校验
    1.勾选的商品:从redis中确认是否勾选
    2.当前的用户:用户对象必须存在
    3.用户的地址:根据用户对象查找用户的地址
    4.支付的方式:确认银联支付还是支付宝支付
3.创建order
    order_id  要我们自己生成
4.创建订单商品表
    order_id
    goods_id
"""

# 在订单orders应用中的views.py模块，定义如下类
from rest_framework.views import APIView
from xiaomishop import settings


class MyAliPay(APIView):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        # 初始化alipay对象
        self.alipay = AliPay(
            appid='2021000119664047',  # 你的支付宝沙箱应用的id
            app_private_key_string=open(settings.APP_PRIVATE_KEY_PATH).read(),  # 你的私钥
            alipay_public_key_string=open(settings.ALIPAY_PUBLIC_KEY_PATH).read(),  # 支付宝公钥
            app_notify_url=None,  # 回调地址
            sign_type='RSA2',  # 签名算法
            debug=True,  # 请求来到支付宝沙箱
        )

    # 定义生成支付地址的方法
    def get_trade_url(self, order_id, total_price):
        order_string = self.alipay.api_alipay_trade_page_pay(
            subject='商家收款',
            out_trade_no=order_id,  # 订单号
            total_amount=total_price,
            return_url='http://127.0.0.1:8000/orders/pay/result/',
            notify_url=None  # 异步通知地址
        )
        return 'https://openapi.alipaydev.com/gateway.do?' + order_string


#  解决空订单问题
class CreateOrder(MyAliPay):
    def post(self, request):
        """
        1.前端传递的数据
        user: this.$store.getters.getUser, {}
        products: this.getCheckGoods, //获取勾选的商品{}
        addr: this.getSelectedAddr(),  地址的id
        payMethod: this.radio, //支付方式：1支付宝 2银联卡
        """
        username = request.data.get("user")["userName"]
        products = request.data.get("products")
        addr_id = request.data.get("addr")
        payMethod = request.data.get("payMethod")
        print("创建订单接收的信息>>>>>", username, "/", products, "/", addr_id, '/', payMethod)
        # 2.校验用户及地址
        try:
            user = Users.objects.get(username=username)
        except Exception as e:
            print(e)
            return Response({"msg": "请先登录", "code": 400})
        try:
            address = Address.objects.get(id=addr_id)
        except Exception as e:
            print(e)
            return Response({"msg": "请确认收货地址", 'code': 400})
        # 3.创建订单id 使用时间戳
        order_id = datetime.now().strftime("%Y%m%d%H%M%S") + str(random.randint(00000000, 99999999)) + str(user.id)
        print("订单号>>>>>>>>", order_id)
        # 总价格   总销量初始值  邮费的初始值
        total_amount = 0
        total_count = 0
        freight = 10
        # 创建订单前  也就是在MySQL操作前  手动开启事务
        with transaction.atomic():  # 开启事务
            point = transaction.savepoint()  # 设置回滚点
            # 将MySQL整个的事务放入try中

            try:
                # 4.创建订单  也就是添加到订单表中
                order = Order.objects.create(
                    order_id=order_id,
                    user_id=user.id,
                    address=address,
                    total_amount=total_amount,
                    freight=10,
                    total_count=total_count,
                    pay_method=payMethod,
                )
                # 5.创建订单商品:
                # 遍历products  购物车里勾选的商品
                for product in products:
                    # 判断库存和商品数量
                    try:
                        pid = product['productID']  # 商品id
                        good = Goods.objects.get(id=pid)
                        # print("商品对象", good)
                    except Exception as e:
                        print(e)
                        return Response({"msg": "商品已下架", 'code': 400})
                    old_count = good.count  # 销量
                    print("销量>>>>>", old_count)
                    old_stock = good.stock  # 库存
                    if product['num'] > old_stock:
                        # 如果销量大于库存   库存不足
                        transaction.savepoint_rollback(point)  # 库存不足  回滚
                        return Response({"msg": '库存不足', 'code': 400})
                    # 创建订单商品前  判断商品的  销量  库存 是否一样,  不一样不能创建订单商品
                    result = Goods.objects.filter(
                        id=product['productID'],
                        stock=old_stock,
                        count=old_count,
                    )
                    if not result:
                        # 此时商品销量 库存 发生改变
                        transaction.savepoint_rollback(point)  # 商品信息发生改变 回滚
                        raise ValueError("前后数据不一致,创建订单失败")

                    # 创建订单商品   添加到订单商品表
                    OrderGoods.objects.create(
                        good_id=pid,
                        count=product['num'],  # 购买数量
                        price=product["price"],
                        order_id=order_id
                    )
                    # 商品库存  及  销量
                    new_stock = old_stock - product['num']  # 总库存
                    new_count = old_count + product['num']  # 总销量
                    # 更新商品库存 及 销量
                    good.count = new_count
                    good.stock = new_stock
                    good.save()  # 保存
                    # 商品的总价格  总销量
                    total_count += product['num']  # 总销量
                    total_amount += product['num'] * product["price"]  # 总价格
                # 更新订单表中的总价格  及 商品总数量
                total_count += freight  # 加上运费
                order.total_amount = total_amount  # 总价格
                order.total_count = total_count  # 商品总数量
                order.save()
            except Exception as e:
                print(e)
                # 该过程任意一处报错  回滚到回滚点
                transaction.savepoint_rollback(point)
                return Response({"msg": "订单提交失败", 'code': 400})
            # 提交事务  操作完成
            transaction.savepoint_commit(point)
        # 将redis中已经支付的商品删除
        redis_conn = redis.Redis()
        # 构建哈希名  和集合名
        cart_key = "cart_%s" % user.id  # 哈希中的key
        cart_selected = "cart_selected_%s" % user.id  # 集合中的key
        for i in products:
            # 删除已经支付的商品
            redis_conn.hdel(cart_key, i['productID'])
            redis_conn.srem(cart_selected, i['productID'])
        redis_conn.close()
        # 调用生成的支付地址
        # order_ = OrderSer(order, many=True)
        trade_url = self.get_trade_url(order_id, order.total_amount)
        return Response({"msg": "下单成功", 'code': 200, 'url': trade_url})


# 处理回调的视图类
class CheckPayResult(MyAliPay):
    def get(self, request):
        """告知买家支付成功"""
        # 获取支付结果的参数   使用query_params 获取支付的结果
        print("支付结果的参数", request.query_params)
        # 获取订单号
        order_id = request.query_params.get("out_trade_no")
        # 根据订单号查询订单支付的结果
        result = self.alipay.api_alipay_trade_query(order_id)
        print("订单支付结果", result)
        if result.get('trade_status') == "TRADE_SUCCESS":
            # 此时说明支付成功
            # 修改订单的支付状态
            order = Order.objects.get(order_id=order_id)
            # 支付状态是  pay_status
            order.pay_status = 1
            order.save()
            return Response({"msg": "支付成功", 'code': 200})
        else:
            return Response({"msg": "支付失败,请重新支付"})

    def post(self, request):
        """
        告知卖家支付的结果
        支付宝沙箱没有这功能,只能等项目上线后才能使用,这里仅做说明
        """
        # 把返回的参数形成字典
        data_dict = {k: v for k, v in request.POST.items()}
        # 此时项目未上线  订单的状态修改无效果
        order_id = data_dict.get("out_trade_no")
        # 获取sign
        sign = data_dict.pop('sign')
        # 对sign进行校验防止伪造
        result = self.alipay.verify(data_dict, sign)
        if result:
            # 说明支付成功
            if data_dict.get('trade_status') == "TRADE_SUCCESS":
                # 支付成功  给支付宝响应
                order = Order.objects.get(order_id=order_id)
                order.pay_status = 1
                order.save()
                return Response({"msg": "支付成功", 'code': 200})
            return Response({"msg": "支付失败", 'code': 400})
        else:
            return Response({"msg": "您已被网警关注", 'code': 200})


# 获取订单详情
class OrderInfo(APIView):
    def post(self, request):
        """
        获取订单详情
        {
        "code": 200,
        'msg': '获取订单数据成功！',
        'orders':[
                    [{},{},...], //一个订单及包含的订单商品
                    [], //第二个订单
                    ...
                ]，
        }
        """
        username = request.data.get("user")["userName"]
        print("获取订单详情>>>>>>username", username)
        try:
            user = Users.objects.get(username=username)
        except Exception as e:
            print(e)
            return Response({"msg": "用户不存在,请先登录!!!", 'code': 400})
        # 查询用户下所有订单
        orders = user.order.all()
        # 定义订单列表order_list
        order_list = []
        # 根据订单查商品
        for order in orders:
            # 根据订单查订单下的商品
            order_goods = order.orderGood.all()
            temp = []  # 用于存放该订单的每一个商品
            for order_good in order_goods:
                temp.append({
                    "productID": order_good.good.id,  # 商品编号
                    "productImg": order_good.good.img,  # 商品图片
                    "productName": order_good.good.sku_name,  # 商品名称
                    "productPrice": order_good.good.price,  # 商品价格
                    "productNum": order_good.count,  # 商品数量
                    "payStatus": order.pay_status,  # 订单状态
                    "orderID": order.order_id,  # 订单编号
                    "Status": "待发货",  #
                    "createdTime": order.created_time,  # 订单时间
                })
            order_list.append(temp)
        return Response({"msg": "获取订单成功", 'code': 200, "orders": order_list})


# 订单支付
class PayOrder(MyAliPay):
    def post(self, request):
        """支付"""
        order_id = request.data.get("orderID")
        total_price = request.data.get("totalPrice")
        # 支付
        url = self.get_trade_url(order_id, total_price)
        return Response({"msg": "正在前往支付", 'code': 302, "pay_url": url})


# 确认收货
class ConfirmReceiveView(APIView):
    def post(self, request):
        order_id = request.data.get("orderID")  # 接收订单编号
        try:
            # 查询 订单  判断是否存在
            order = Order.objects.get(order_id=order_id)
            # 修改订单状态
            order.pay_status = 3
            order.save()
        except Exception as e:
            print(e)
            return Response({"msg": "订单不存在", 'code': 400})
        return Response({"msg": "收货成功", 'code': 200})


# 删除订单商品
class DelOrderProductView(APIView):
    def post(self, request):
        # 接收订单编号    和  商品编号
        order_id = request.data.get("orderID")
        pid = request.data.get("productID")
        print("pid>>>>>>>>>>>>>>>>>>>>>", pid)
        try:
            order = Order.objects.get(order_id=order_id)
        except Exception as e:
            print(e)
            return Response({"msg": "订单不存在", 'code': 400})
        order_goods = order.orderGood.all()
        if len(order_goods) > 1:
            # 删除一个订单商品
            Goods.objects.get(id=pid).delete()
            return Response({"msg": "订单商品删除成功", "code": 200})
        else:
            # 只有一个商品 删除订单
            Order.objects.get(order_id=order_id).delete()
            return Response({"msg": "订单删除成功", "code": 200})
